package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.domain.entity.RestaurantBalanceDetail;
import com.ruoyi.common.core.domain.entity.RestaurantCustomer;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.RestaurantBalanceDetailMapper;
import com.ruoyi.system.mapper.RestaurantCustomerMapper;
import com.ruoyi.system.service.RestaurantCustomerService;
import com.ruoyi.system.service.enums.ChangeBalanceType;
import com.ruoyi.system.service.enums.CustomerType;
import com.ruoyi.system.service.req.CustomerQueryDTO;
import com.ruoyi.system.service.req.InnerCustomerAddDTO;
import com.ruoyi.system.service.req.NormalCustomerAddDTO;
import com.ruoyi.system.service.req.UpdateCustomerDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: ruohao
 * @Date: 2023/8/11
 **/
@Service
public class RestaurantCustomerServiceImpl implements RestaurantCustomerService {

    private static final Logger log = LoggerFactory.getLogger(RestaurantCustomerServiceImpl.class);

    @Resource
    private RestaurantCustomerMapper restaurantCustomerMapper;

    @Resource
    private RestaurantBalanceDetailMapper restaurantBalanceDetailMapper;

    @Override
    public List<RestaurantCustomer> getNormalCustomer(CustomerQueryDTO customerQueryDTO) {
        RestaurantCustomer queryDO = new RestaurantCustomer();
        queryDO.setCustomerName(customerQueryDTO.getCustomerName());
        queryDO.setCustomerId(customerQueryDTO.getCustomerId());
        queryDO.setHouseNumber(customerQueryDTO.getHouseNumber());
        queryDO.setLocation(customerQueryDTO.getLocation());
        queryDO.setPhone(customerQueryDTO.getPhone());
        Map<String, Object> balanceRange = new HashMap<>();
        balanceRange.put("maxBalance", customerQueryDTO.getMaxBalance());
        balanceRange.put("minBalance", customerQueryDTO.getMinBalance());
        queryDO.setParams(balanceRange);
        return restaurantCustomerMapper.selectRestaurantCustomerList(queryDO);
    }

    @Override
    public List<RestaurantCustomer> getInnerCustomer(CustomerQueryDTO customerQueryDTO) {
        RestaurantCustomer queryDO = new RestaurantCustomer();
        queryDO.setCustomerName(customerQueryDTO.getCustomerName());
        queryDO.setCustomerId(customerQueryDTO.getCustomerId());
        queryDO.setType(CustomerType.INNER.getCode());
        queryDO.setHouseNumber(customerQueryDTO.getHouseNumber());
        queryDO.setLocation(customerQueryDTO.getLocation());
        queryDO.setPhone(customerQueryDTO.getPhone());
        Map<String, Object> balanceRange = new HashMap<>();
        balanceRange.put("maxBalance", customerQueryDTO.getMaxBalance());
        balanceRange.put("minBalance", customerQueryDTO.getMinBalance());
        queryDO.setParams(balanceRange);
        return restaurantCustomerMapper.selectRestaurantCustomerList(queryDO);
    }

    @Override
    public List<RestaurantCustomer> getCustomer(RestaurantCustomer restaurantCustomer) {
        return restaurantCustomerMapper.selectRestaurantCustomerList(restaurantCustomer);
    }

    @Override
    public RestaurantCustomer getNormalCustomerById(Long id) {
        return restaurantCustomerMapper.selectNormalCustomerById(id);
    }

    @Override
    public RestaurantCustomer getCustomerByUserId(String customerId) {
        return restaurantCustomerMapper.selectCustomerByUserId(customerId);
    }

    @Override
    public RestaurantCustomer getInnerCustomerById(Long id) {
        return restaurantCustomerMapper.selectInnerCustomerById(id);
    }

    @Override
    public Boolean createInnerCustomer(InnerCustomerAddDTO innerCustomerAddDTO, SysUser operator) {
        RestaurantCustomer createDO = InnerCustomerAddDTO.convertToDO(innerCustomerAddDTO);
        createDO.setCreateBy(operator.getUserName());
        return restaurantCustomerMapper.insertRestaurantCustomer(createDO) == 1;
    }

    @Override
    public Boolean createNormalCustomer(NormalCustomerAddDTO normalCustomerAddDTO, SysUser operator) {
        RestaurantCustomer createDO = NormalCustomerAddDTO.convertToDO(normalCustomerAddDTO);
        createDO.setCreateBy(operator.getUserName());
        return restaurantCustomerMapper.insertRestaurantCustomer(createDO) == 1;
    }

    @Override
    public Boolean createCustomer(RestaurantCustomer restaurantCustomer) {
        return restaurantCustomerMapper.insertRestaurantCustomer(restaurantCustomer) == 1;
    }

    @Override
    public Boolean updateCustomerByUserId(RestaurantCustomer restaurantCustomer) {
        return restaurantCustomerMapper.updateRestaurantCustomerByUserId(restaurantCustomer) == 1;
    }

    @Override
    public Boolean updateCustomer(UpdateCustomerDTO updateCustomerDTO, SysUser operator) {
        RestaurantCustomer updateDo = RestaurantCustomer.builder()
            .id(updateCustomerDTO.getId())
            .houseNumber(StringUtils.isBlank(updateCustomerDTO.getHouseNumber()) ? null : updateCustomerDTO.getHouseNumber())
            .customerName(StringUtils.isBlank(updateCustomerDTO.getCustomerName()) ? null : updateCustomerDTO.getCustomerName())
            .phone(StringUtils.isBlank(updateCustomerDTO.getPhone()) ? null : updateCustomerDTO.getPhone())
            .build();
        updateDo.setUpdateBy(operator.getUserName());
        return restaurantCustomerMapper.updateRestaurantCustomer(updateDo) == 1;
    }

    @Override
    public Boolean comsumeCustomerBalance(Long id, BigDecimal amount, String reason, SysUser operator) {
        RestaurantCustomer customer = restaurantCustomerMapper.selectRestaurantCustomerById(id);
        if (customer == null) {
            log.warn("客户账户 消费 找不到这个用户 id {} amount {} reason {}", id, amount, reason);
            throw new ServiceException("找不到这个用户");
        }
        if (amount.compareTo(customer.getBalance()) == 1) {
            log.warn("客户账号 消费 用户余额不足 id {} amount {} reason {} customer {}", id, amount, reason, JSON.toJSONString(customer));
            throw new ServiceException("用户余额不足");
        }
        List<RestaurantBalanceDetail> details = restaurantBalanceDetailMapper.selectRestaurantBalanceDetailList(RestaurantBalanceDetail.builder()
                .reason(reason)
                .customerId(id).build());
        if (!CollectionUtils.isEmpty(details)) {
            log.warn("客户账号 消费 已经消费过一次 幂等过滤 id {} amount {} reason {}", id, amount, reason);
            return true;
        }
        RestaurantCustomer customerUpdateDO = RestaurantCustomer.builder()
            .id(customer.getId())
            .balance(customer.getBalance().subtract(amount))
            .build();
        int result = restaurantCustomerMapper.updateRestaurantCustomer(customerUpdateDO);
        if (result != 1) {
            log.warn("客户账户 消费 更新客户余额失败 id {} amount {} reason {}", id, amount, reason);
            throw new ServiceException("更新客户余额失败");
        }
        RestaurantBalanceDetail restaurantBalanceDetailCreateDO = RestaurantBalanceDetail.builder()
            .amount(amount)
            .reason(reason)
            .location(operator.getLocation())
            .customerId(Long.parseLong(customer.getCustomerId()))
            .build();
        restaurantBalanceDetailCreateDO.setType("用户消费");
        result = restaurantBalanceDetailMapper.insertRestaurantBalanceDetail(restaurantBalanceDetailCreateDO);
        if (result != 1) {
            log.warn("客户账户 消费 插入余额明细失败 id {} amount {} reason {}", id, amount, reason);
            throw new ServiceException("插入余额明细失败");
        }
        return Boolean.TRUE;
    }

    @Override
    public RestaurantBalanceDetail changeCustomerBalance(Long id, BigDecimal amount, String reason, Integer type, SysUser operator) {
        RestaurantCustomer customer = restaurantCustomerMapper.selectRestaurantCustomerById(id);
        if (customer == null) {
            log.warn("客户账户 改变账户余额 找不到这个用户 id {} amount {} reason {} operator {}", id, amount, reason, JSON.toJSONString(operator));
            throw new ServiceException("找不到这个用户");
        }
        if (ChangeBalanceType.REDUCE.getCode().equals(type) && amount.compareTo(customer.getBalance()) == 1) {
            log.warn("客户账号 改变账户余额 用户余额不足 id {} amount {} reason {} customer {} operator {}", id, amount, reason, JSON.toJSONString(customer), JSON.toJSONString(operator));
            throw new ServiceException("用户余额不足");
        }
        RestaurantBalanceDetail restaurantBalanceDetail = new RestaurantBalanceDetail();
        restaurantBalanceDetail.setCustomerId(id);
        restaurantBalanceDetail.setAmount(amount);
        restaurantBalanceDetail.setReason(reason);
        restaurantBalanceDetail.setLocation(operator.getLocation());
        restaurantBalanceDetail.setCreateBy(operator.getNickName());
        RestaurantCustomer customerUpdateDO = new RestaurantCustomer();
        customerUpdateDO.setId(customer.getId());
        customerUpdateDO.setUpdateBy(SecurityUtils.getLoginUser().getUser().getNickName());
        if (ChangeBalanceType.ADD.getCode().equals(type)) {
            customerUpdateDO.setBalance(customer.getBalance().add(amount));
            restaurantBalanceDetail.setType("手动增加");
        } else if (ChangeBalanceType.REDUCE.getCode().equals(type)) {
            customerUpdateDO.setBalance(customer.getBalance().subtract(amount));
            restaurantBalanceDetail.setType("手动减少");
        } else {
            throw new ServiceException("没有这个操作");
        }
        int detailResult = restaurantBalanceDetailMapper.insertRestaurantBalanceDetail(restaurantBalanceDetail);
        if (detailResult != 1) {
            log.warn("客户账号 改变账户余额 增加变更记录失败 id {} amount {} reason {} customer {} operator {}", id, amount, reason, JSON.toJSONString(customer), JSON.toJSONString(operator));
            throw new ServiceException("增加变更记录失败");
        }
        int customerResult = restaurantCustomerMapper.updateRestaurantCustomer(customerUpdateDO);
        if (customerResult != 1) {
            log.warn("客户账号 改变账户余额 改变账号数据库余额失败 id {} amount {} reason {} customer {} operator {}", id, amount, reason, JSON.toJSONString(customer), JSON.toJSONString(operator));
            throw new ServiceException("改变账号数据库余额失败");
        }
        return restaurantBalanceDetail;
    }

    @Override
    public int deleteByIds(List<Long> ids) {
        return restaurantCustomerMapper.deleteRestaurantCustomerByIds(ids);
    }
}
